package com.skyyan.netty.jjf.server;

import com.skyyan.netty.jjf.codec.JjfMessageDecoder;
import com.skyyan.netty.jjf.codec.JjfMessageEncoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.BindException;
import java.util.concurrent.TimeUnit;

public class JjfServer {

    private static final Logger log = LoggerFactory.getLogger(JjfServer.class);

    // 服务端配置
    private static final int DEFAULT_PORT = 1883;
    private static final int BOSS_THREADS = 1;
    private static final int WORKER_THREADS = 4;

    // 超时配置（秒）
    private static final int READER_IDLE_TIME = 120;  // 读超时
    private static final int WRITER_IDLE_TIME = 30;   // 写超时
    private static final int ALL_IDLE_TIME = 150;     // 总超时

    private final int port;

    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel serverChannel;

    public JjfServer() {
        this(DEFAULT_PORT);
    }

    public JjfServer(int port) {
        this.port = port;
    }

    /**
     * 启动服务端
     */
    public void start() throws Exception {
        bossGroup = new NioEventLoopGroup(BOSS_THREADS);
        workerGroup = new NioEventLoopGroup(WORKER_THREADS);

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline()
                                    // 日志处理器（可选）
                                    .addLast("logger", new LoggingHandler(LogLevel.DEBUG))

                                    // 空闲状态检测
//                                    .addLast("idleStateHandler", new IdleStateHandler(
//                                            READER_IDLE_TIME, WRITER_IDLE_TIME, ALL_IDLE_TIME, TimeUnit.SECONDS))

                                    // 协议编解码器
                                    .addLast("decoder", new JjfMessageDecoder())
                                    .addLast("encoder", new JjfMessageEncoder())

                                    // 业务处理器
                                    .addLast("serverHandler", new ServerHandler());
                        }
                    });

            // 绑定端口并启动服务
            log.info("正在启动服务端，监听端口: {}", port);
            ChannelFuture future = bootstrap.bind(port).sync();

            if (future.isSuccess()) {
                serverChannel = future.channel();
                log.info("服务端启动成功，监听端口: {}", port);
            } else {
                throw new RuntimeException("服务端启动失败", future.cause());
            }

            // 等待服务端通道关闭
            serverChannel.closeFuture().sync();
        } catch (Exception e) {
            if (e instanceof BindException || (e.getCause() != null && e.getCause() instanceof BindException)) {
                log.error("端口 {} 已被占用，请检查是否有其他程序正在运行或更改端口号", port);
            } else {
                log.error("服务端启动过程中发生异常", e);
            }
            throw e;
        }
    }

    /**
     * 关闭服务端
     */
    public void shutdown() {
        log.info("正在关闭服务端...");

        if (serverChannel != null) {
            serverChannel.close();
        }

        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }

        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }

        log.info("服务端已关闭");
    }

    public static void main(String[] args) {
        int port = DEFAULT_PORT;
        if (args.length > 0) {
            try {
                port = Integer.parseInt(args[0]);
            } catch (NumberFormatException e) {
                log.error("端口号格式错误，使用默认端口: {}", DEFAULT_PORT);
            }
        }

        JjfServer server = new JjfServer(port);
        try {
            server.start();
        } catch (Exception e) {
            if (e instanceof BindException || (e.getCause() != null && e.getCause() instanceof BindException)) {
                // 已经在start方法中记录过绑定异常，这里不需要重复记录
                System.exit(1);
            } else {
                log.error("服务端启动失败", e);
                System.exit(1);
            }
        }
    }
}
